<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{{appTitle}}</title>
    <!--<link rel="stylesheet" href="https://unpkg.com/element-plus@2.4.4/dist/index.css"/>-->
    <link rel="stylesheet" href="static/assets/index.css"/>
    <!--<script src="https://unpkg.com/vue@3.3.12/dist/vue.global.js"></script>-->
    <script src="static/assets/vue.global.js"></script>
    <!--<script src="https://unpkg.com/vue-i18n@9.8.0/dist/vue-i18n.global.js"></script>-->
    <script src="static/assets/vue-i18n.global.js"></script>
    <!--<script src="https://unpkg.com/element-plus@2.4.4/dist/index.full.min.js"></script>-->
    <script src="static/assets/index.full.min.js"></script>
    <!--<script src="https://unpkg.com/@element-plus/icons-vue@2.3.1/dist/index.iife.min.js"></script>-->
    <script src="static/assets/index.iife.min.js"></script>
    <!--<script src="https://unpkg.com/clipboard@2.0.11/dist/clipboard.min.js"></script>-->
    <script src="static/assets/clipboard.min.js"></script>
    <!--<script src="https://unpkg.com/axios@1.6.2/dist/axios.min.js"></script>-->
    <script src="static/assets/axios.min.js"></script>
    <script src="static/assets/fabric.min.js"></script>
    <script src="static/assets/jszip.min.js"></script>
    <script src="static/assets/FileSaver.min.js"></script>
    <!--引入样式--> 
    <link rel="stylesheet" href="../extensions/ComfyUI_Lam/static/css/app.css" />
</head>
<body>
    <div id="app" style="display: none;">
        <el-main  class="aigc-layout">
            <div class="aigc-head">
                <div class="head-title">
                    <el-image src="{{appLogo}}"  style="height: 100%;width: auto;">
                        <template #error>
                            <div class="head-title">
                                {{appTitle}}
                            </div>
                        </template>
                    </el-image>
                    <template v-if="'{{appLogo}}'.length>10">
                        | {{appTitle}}
                    </template>
                </div>
                <div class="aigc-head__left-block"></div>
                <div class="aigc-head__right-block" v-if="isShowAdmin()">
                    <el-popover placement="bottom" :width="300" trigger="click" >
                        <template #reference>
                            <div style="color: aliceblue;" id="contact_administrator" class="aigc-head__right-block--qun aigc-head__right-block--commonbtn aigc-head__right-block--hover">
                                联系管理员 </div>
                        </template>
                        <template #default>
                            <div class="ant-popover-content">
                                <div class="ant-popover-arrow"><span class="ant-popover-arrow-content"></span></div>
                                <div class="ant-popover-inner" role="tooltip">
                                    <div class="ant-popover-inner-content">
                                        <div class="add-soci">
                                            <div class="add-text">扫码添加管理员微信</div><img class="qr-code" style="width: 100%;"
                                                src="/lam/getImage?type=wechat&&name=admin_qr_code.jpg">
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </template>
                    </el-popover>
                    <div class="aigc-head__right-block--avatarbox">
                    <el-avatar class="aigc-head__right-block--avatar" src="https://himg.bdimg.com/sys/portraith/item/public.1.e8294af1.YF07P1v3sOMXm56wbOMh9w"/>
                    </div>
                </div>
            </div>
            <!-- <div  class="aigc-tab">
                <template v-for="(value, key, index) in commandList" :key="key">
                <div :class="'aigc-tab__item'+ (key==activeKey?' active':'')" @click="clickTab(key)">
                    <span>{{key}}</span>
                </div>
                </template>
            </div> -->
            <div class="aigc-main">
                <div  class="aigc-main__left-content">
                    <div  class="aigc-main__left-content--top-wrap">
                        <div  class="aigc-main__left-content--top-right step_5 step_7">
                            <div  class="aigc-main__left-content--nodata" >
                                <el-progress v-if="form.status=='waiting'" type="circle" :percentage="form.percentage" :status="percenStatus"  >
                                    <template #default="{ percentage }">
                                        <div class="percentage-value">{{ percentage }}%</div>
                                        <div class="percentage-label">{{percenStatus=='warning'?'等待生成':'生成中'}}</div>
                                      </template>
                                </el-progress>
                                <section v-else-if="form.output.images.length>0" class="aigc-preview"  >
                                    <el-carousel class="aigc-preview__img" style="display: block;height: 100%;"  :interval="5000" arrow="always" :autoplay="false">
                                        <el-carousel-item  v-for="(item,index) in form.output.images" :key="index">
                                            <el-image style="width: 100%;height: 100%;" :preview-src-list="[item]" :preview-teleported="true"  :src="item" fit="contain" ></el-image>
                                        </el-carousel-item>
                                    </el-carousel>
                                    <!-- <el-image class="aigc-preview__img"  src="../view?filename=ComfyUI_03170_.png&type=input&subfolder=" fit="contain" ></el-image> -->
                                </section>
                                <p v-else >生成预览区</p>
                            </div>
                        </div>
                    </div>
                    <div  class="aigc-main__left-content--bottom-wrap step_2_empty">
                        <div   class="aigc-container">
                            <div  class="aigc-container__formula">
                                <div  class="aigc-container__tabs-box">
                                    <div  class="aigc-container__sub-tab active-sub-tab">历史记录</div>
                                </div>
                                <div  class="aigc-container__recomm-fml" v-infinite-scroll="loadHistory" :infinite-scroll-disabled="disabled" >
                                    <template v-for="(item,index) in historyList">
                                        <div class="item-box step_2 aigc-container__fml-item" >
                                            <el-image v-if="item.images&&item.images.length>0" class="cover-img" :src="item.images[0]" :zoom-rate="1.2" :max-scale="7" :min-scale="0.2"
                                              :preview-src-list="item.images" fit="cover" :preview-teleported="true" >
                                              <template #error>
                                                <div class="el-image__error">
                                                    图片丢失
                                                </div>
                                               </template>
                                            </el-image>
                                            <el-image v-else-if="item.texts&&item.texts.length>0" class="cover-img" :src="item.images[0]" :zoom-rate="1.2" :max-scale="7" :min-scale="0.2"
                                                :alt="item.texts[0]" fit="cover" :preview-teleported="true" >
                                                <template #error>
                                                <el-popover placement="top-start" title="预览文本" :width="200"
                                                    trigger="hover" :content="item.texts[0]" >
                                                    <template #reference>
                                                        <div class="el-image__error" >
                                                            {{item.texts[0]}}
                                                        </div>
                                                    </template>
                                                </el-popover>
                                                </template>
                                            </el-image>
                                            <div  class="bottom" style="color: #fff;">
                                                {{item.command.command}}({{item.images.length}})
                                                <el-popconfirm title="是否应用此参数?" @confirm="confirmSetParam(item.command)" >
                                                    <template #reference>
                                                        <el-icon><Edit /></el-icon>
                                                    </template>
                                                </el-popconfirm>
                                                <el-popconfirm v-if="item.images.length>0" title="是否下载任务图片?" @confirm="handleDownload(item.files,item.prompt_id)" >
                                                    <template #reference>
                                                        <el-icon><Download /></el-icon>
                                                    </template>
                                                </el-popconfirm>
                                            </div>
                                        </div>
                                    </template>
                                </div><!---->
                                <p v-if="loading">Loading...</p>
                                <p v-if="noMore">No more</p>
                            </div><!----><!----><!----><!---->
                        </div>
                    </div>
                </div>
                <div  class="aigc-main__right-params">
                    <!--滚动条-->
                    <div class="aigc-layright__top" style="overflow-y: scroll;height: 78vh;">
                        <div class="aigc-top">
                            <el-form ref="form" :model="form" label-width="70px" label-position="top" >
                            <el-form-item label="功能选择">
                                <el-select style="width: 100%;" v-model="activeKey" @change="clickTab(activeKey)" placeholder="请选择功能" >
                                    <template v-for="(value, key, index) in commandList" :key="key">
                                        <el-option :value="key">{{key}}</el-option>
                                    </template>
                                </el-select>
                            </el-form-item>
                            <el-form-item label="总任务数量">
                                <el-rate v-model="queue_remaining" :max="11"   :icons="['UserFilled','UserFilled','UserFilled']" :void-icon="'User'" disabled-void-icon="User"  disabled />
                            </el-form-item>
                            <template v-for="(param,paramKey, paramindex) in paramList ">
                                <div class="aigc-prompt" v-if="param.type == 'customtext'||paramKey == 'prompt' || paramKey == 'negative'">
                                    <div class="aigc-prompt__head">
                                        <div class="aigc-prompt__head--text">{{param.zhName}}</div>
                                        <div class="aigc-prompt__head--clear" @click="clearValue(param)"> 清除 </div>
                                    </div>
                                    <el-form-item label="" label-width="0px">
                                        <el-input type="textarea" v-model="param.value" :placeholder="'输入'+param.zhName"
                                        rows="6" show-word-limit ></el-input>
                                    </el-form-item>
                                </div>
                            </template>
                            <div  class="aigc-advanced">
                                <div  class="aigc-advanced__mid--text" style="font-weight: bold;font-size: medium;"> 其他参数 </div>
                                    <template v-for="(param,paramKey,paramindex) in paramList ">
                                    <el-form-item :label="param.zhName" v-if="param.options">
                                        <el-select v-model="param.value" :placeholder="'请选择'+param.zhName">
                                            <el-option v-for="(value, key, index) in param.options" :key="value" :label="key" :value="value"></el-option>
                                        </el-select>
                                    </el-form-item>
                                    <el-form-item :label="param.zhName" v-else-if="param.type == 'text'">
                                        <el-input v-model="param.value" :placeholder="'请输入'+param.zhName" >
                                        </el-input>
                                    </el-form-item>
                                    <el-form-item :label="param.zhName" v-else-if="param.type == 'seed'">
                                        <el-input v-model="param.value" :placeholder="'请输入'+param.zhName" >
                                            <template #append>
                                                <el-button icon="Refresh" @click="refreshSeed(param)" />
                                              </template>
                                        </el-input>
                                    </el-form-item>
                                    <el-form-item :label="param.zhName" v-else-if="param.type == 'image'">
                                        <div :class="param.fileList.length>0?'image-view':''">
                                            <el-upload
                                                v-model:file-list="param.fileList" :limit="1" drag
                                                action="../upload/image" name="image" method="post"  :data="{'overwrite': true,'type':'input'}"
                                                list-type="picture-card" :on-preview="(val) => handlePictureCardPreview(val, param?.maskKey)" :before-upload="beforeAvatarUpload"
                                                :on-success="(val)=>updateSuccess(val,paramKey)"  :on-remove="(val) => handleRemove(val, paramKey)">
                                                <el-icon class="el-icon--upload" :size="80"><upload-filled /></el-icon>
                                            </el-upload>
                                        </div>
                                    </el-form-item>
                                    <el-form-item :label="param.zhName" v-else-if="param.type == 'number'">
                                        <el-input-number v-model="param.value" :min="param.min" :max="param.max" :step="param?.step"></el-input-number>
                                    </el-form-item>
                                    <el-form-item :label="param.zhName" v-else-if="param.type == 'slider'">
                                        <el-slider v-model="param.value" :min="param.min" :max="param.max" :step="param?.step"></el-slider>
                                    </el-form-item>
                                    <el-form-item :label="param.zhName" v-else-if="param.type == 'switch'">
                                        <el-switch v-model="param.value" :active-value="param.onVal" :inactive-value="param.offVal"></el-switch>
                                    </el-form-item>
                                    <el-form-item :label="param.zhName" v-else-if="param.type == 'color'">
                                        <el-color-picker v-model="param.value" />
                                    </el-form-item>
                                    <el-form-item :label="param.zhName" v-else-if="param.type == 'checkbox'">
                                        <el-checkbox-group v-model="param.value">
                                            <el-checkbox v-for="(value, key, index) in param.options"
                                             :label="key" :value="value" :name="paramKey"></el-checkbox>
                                        </el-checkbox-group>
                                    </el-form-item>
                                    <el-form-item :label="param.zhName" v-else-if="param.type == 'radio'">
                                        <el-radio-group v-model="param.value">
                                            <el-radio v-for="(value, key, index) in param.options"
                                             :label="key" :value="value"></el-radio>
                                          </el-radio-group>
                                    </el-form-item>
                                    </template>
                            </div>
                            </el-form>
                        </div>
                        
                    </div>
                    <el-dialog v-model="dialogVisible" :title="maskKey? '遮罩画板':'图片预览'">
                        <div class="mask_edit_btn" style="display: -webkit-box;" v-if="maskKey">
                        <el-slider v-model="brushSize" :min="5" :max="200" :step="5" style="width:40%;margin: 0 10px;" @change="changeSize" ></el-slider>
                        <el-button style="margin: 0 10px;" type="info" @click="clearCanvas">清除画板</el-button>
                        <el-button style="margin: 0 10px;" type="info" @click="saveCanvas">应用遮罩</el-button>
                        </div>
                        <div v-if="maskKey">
                            <canvas id="canvas" ></canvas>
                        </div>
                        <div v-else >
                            <img w-full :src="dialogImageUrl" alt="图片预览" style="width: 100%;" />
                        </div>
                    </el-dialog>
                    <div class="aigc-main__btn-box step_4">
                        <el-button v-if="form.status!='prepare'" :class="'aigc-main__btn-box--merge'" style="height: 100%;background: linear-gradient(to bottom right, rgb(224 224 224), rgb(244 85 85));" 
                            @click="cancelTask" :disabled="!isConnect" >
                            <div class="text"><span class="upper" >取消任务</span></div>
                        </el-button>
                        <el-button v-else :class="'aigc-main__btn-box--merge'+(form.status!='prepare'?' disable':'')" style="height: 100%;" @click="startTask" :disabled="!isConnect">
                            <div class="text"><span class="upper" >立即生成</span></div>
                        </el-button>
                    </div>
                </div>
            </div>
        </el-main>
    </div>
</body>
<script>
function formatTime(seconds) {
    const days = Math.floor(seconds / (3600 * 24));
    seconds -= days * 3600 * 24;
    const hours = Math.floor(seconds / 3600);
    seconds -= hours * 3600;
    const minutes = Math.floor(seconds / 60);
    seconds -= minutes * 60;

    const formattedDays = days > 0 ? days + ':' : '';
    const formattedHours = hours.toString().padStart(2, '0') + ':';
    const formattedMinutes = minutes.toString().padStart(2, '0') + ':';
    const formattedSeconds = seconds.toString().padStart(2, '0') + '';

    let result = formattedDays + formattedHours + formattedMinutes + formattedSeconds;
    return result;
}


function getParams(url) {
  const regex = /[?&]([^=#]+)=([^&#]*)/g;
  const params = {};
  let match;
  while (match = regex.exec(url)) {
    params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
  }
  return params;
}

let openId='{{openId}}';

const app = Vue.createApp({
    data() {
        return {
            commandList:[],
            activeKey:'',
            paramList:[],
            brushSize:20,
            canvas:null,
            dialogVisible:false,
            dialogImageUrl:'',
            dialogImageName:'',
            maskKey:'',
            historyList:[],
            queue_remaining:0,
            page_number:1,
            noMore:false,
            loading:false,
            disabled:false,
            isNotData:false,
            isConnect:false,
            isSuccess:false,
            form: {
                openId:'',
                command:'',
                status:"prepare",
                prompt_id:'',
                percenStatus:'warning',
                percentage:0,
                output:{images:[],texts:[]},
                nodeIds:[],
                doneNodeIds:[]
            }
        }
    },
    mounted: function() {
        if(openId){
            this.initMain();
        }else{
            this.authUser();
        }
    },
    watch:{
        loading(newVal, oldVal) {
            this.disabled = (newVal||this.noMore)
        },
        noMore(newVal, oldVal) {
            this.disabled = (newVal||this.loading)
        },
    },
    created() {
        
    },
    methods: {
        initMain(){
            this.loadData();
            document.getElementById("app").style.display = "block";
            this.initWebSocket();
            this.getHistorys();
        },
        authUser(msg=''){
            let that = this;
            ElementPlus.ElMessageBox.alert(`
            <div class="box-title">微信扫码关注公众号获取授权码</div>
            <img class="qrcode" src="{{qrcodeUrl}}" />
            <div class="el-input el-input-group el-input-group--append">
                <input class="el-input__inner" type="text" autocomplete="off" maxlength="6" tabindex="0" placeholder="输入授权码" id="code_input_id">
            </div>
            <div class="box-title" style="color: #ffb3b3;">`+msg+`</div>
            `, 
            "", {
            showClose:false,
            showCancelButton:false,
            showConfirmButton:true,
            dangerouslyUseHTMLString: true
          })
            .then(() => {
              let code=document.getElementById("code_input_id").value;
              if(code.length!=6){
                that.authUser('验证码长度不正确！');
                return ;
              }
              that.getUserOpenId(code);
            })
        },
        isShowAdmin(){
            if('pywebview' in window){
                if(pywebview.api.isLogin()){
                    return true;
                }
            }
            return false;
        },
        initWebSocket(){
            var that = this;
            var websocket = null;
            //var socketId = "ws-" + new Date().getTime();
            // 判断当前浏览器是否支持WebSocket， springboot是项目名
            if ('WebSocket' in window) {
                var host = window.location.host;
                websocket = new WebSocket("ws://" + host + '/ws?clientId=' + openId);
            } else {
                console.error("不支持WebSocket");
            }
            // 连接发生错误的回调方法
            websocket.onerror = function (e) {
                console.error("WebSocket连接发生错误");
            };
            // 连接成功建立的回调方法
            websocket.onopen = function () {
                // 获取所有在线用户
                console.log("WebSocket连接成功");
                that.isConnect=true;
                
            }
            // 接收到消息的回调方法
            websocket.onmessage = async function (event) {
                if (event.data == null || event.data == "" || event.data instanceof Blob) {
                    return;
                }
                var messageJson = eval("(" + event.data + ")");
                if(messageJson['type']=='crystools.monitor'){
                    return 
                }
                console.log('messageJson',messageJson)
                if(messageJson['type']=="status"){
                    that.queue_remaining=messageJson['data']['status']['exec_info']['queue_remaining'];
                }else if(messageJson['type']=="execution_start"){
                    if(that.form.prompt_id==messageJson['data']['prompt_id']){
                        that.form.percenStatus='success';
                    }
                }else if(messageJson['type']=="execution_cached"){
                    if(that.form.prompt_id==messageJson['data']['prompt_id']){
                        that.form.doneNodeIds=messageJson['data']['nodes'];
                    }
                }else if(messageJson['type']=="executing"){
                    if(that.form.prompt_id==messageJson['data']['prompt_id']){
                        let node=messageJson['data']['node'];
                        if(that.form.executing){
                            that.form.doneNodeIds.push(that.form.executing);
                        }
                        if(!messageJson['data']['node']){
                            that.form.status='prepare';
                            that.form.percenStatus='warning';
                            that.form.percentage=0;
                            that.form.executing='';
                            that.form.doneNodeIds=[];
                            that.form.nodeIds=[];
                            if(that.isSuccess){
                                that.isSuccess=false
                                setTimeout(() => {
                                    that.page_number=1;
                                    that.getHistorys();
                                }, 1000)
                            }
                        }else{
                            that.form.executing=node;
                        }
                    }
                }else if(messageJson['type']=='progress'){
                    if(that.form.prompt_id==messageJson['data']['prompt_id']){
                        let max=messageJson['data']['max'];
                        let value=messageJson['data']['value'];
                        let node=messageJson['data']['node'];
                        let percentage=0;
                        if(that.form.executing==node){
                            percentage=parseFloat(value/max);
                        }
                        that.form.percentage=parseInt((that.form.doneNodeIds.length+percentage)/that.form.nodeIds.length*100);
                    }
                }else if(messageJson['type']=='execution_success'){
                    if(that.form.prompt_id==messageJson['data']['prompt_id']){
                        that.isSuccess=true;
                    }
                }else if(messageJson['type']=='executed'){
                    if(that.form.prompt_id==messageJson['data']['prompt_id']){
                        let node_output='output' in messageJson['data']?messageJson['data']['output']:{};
                        let images=[];
                        let texts=[];
                        if('outputImg' in node_output){
                            for(let img of node_output?.outputImg){
                                let url='../view?filename='+img.filename+'&type='+img.type+'&subfolder='+img.subfolder+'&rand='+Math.random();
                                images.push(url)
                            }
                        }else if("wechat_text" in node_output){
                            texts.push(...node_output.wechat_text);
                        }
                        if(images.length>0||texts.length>0){
                            that.form.output={images:images,texts:texts};
                        }
                    }
                }
            }

            // 连接关闭的回调方法
            websocket.onclose = function () {
                console.error("WebSocket连接关闭");
                that.openCloseMsg();
            }
        },
        openCloseMsg(){
            var that = this;
            that.isConnect=false;
            ElementPlus.ElMessage({
                showClose: true,
                duration:0,
                message: '服务器断开连接，关闭消息尝试重连',
                type: 'error',
                onClose:()=>{
                    that.initWebSocket();
                }
            })
        },
        loadData() {
            var that = this;
            axios.get('../wechatauth/getCommands')
                .then(function(response) {
                    console.log(response);
                    if(response.status == 200){
                        that.commandList = response.data;
                        that.clickTab(Object.keys(response.data)[0])
                    }
                })
                .catch(function(error) {
                    console.log(error);
                    ElementPlus.ElMessage.error(error);
            })
        },
        clickTab(key) {
            this.activeKey=key;
            if(this.commandList[key]){
                this.paramList=this.commandList[key].params;
                for(let paramKey in this.paramList){
                    this.paramList[paramKey]['value']=this.paramList[paramKey]?.default;
                    if(this.paramList[paramKey].type=='image'){
                        this.paramList[paramKey]['fileList']=[];
                    }
                }
            }
        },
        clearValue(param){
            param.value='';
        },
        refreshSeed(param){
            param.value=Math.floor(Math.random() * 1000000000000000);
        },
        handlePictureCardPreview(uploadFile,maskKey){
            this.dialogImageUrl = uploadFile.url;
            this.dialogImageName = uploadFile.name;
            this.dialogVisible = true;
            this.maskKey=maskKey;
            if(this.maskKey){
                this.initCanvas(uploadFile.url);
            }else{
                this.canvas=null;
            }
        },
        handleRemove(uploadFile,paramKey){
            this.paramList[paramKey]['value']='';
        },
        beforeAvatarUpload(rawFile){
            // 判断文件格式不为图片的
            if (rawFile.type !== 'image/png' && rawFile.type !== 'image/jpg' && rawFile.type !== 'image/jpeg') {
                ElementPlus.ElMessage.error('请上传图片文件!');
                return false
            }
            // else if (rawFile.size / 1024 / 1024 > 2) {
            //     ElementPlus.ElMessage.error('Avatar picture size can not exceed 2MB!')
            //     return false
            // }
            return true
        },
        updateSuccess(data,paramKey){
            this.paramList[paramKey]['value']=data.subfolder? (data.type+'/'+data.name):(data.type+'/'+data.subfolder+'/'+data.name)
        },
        changeSize(value) {
            this.canvas.freeDrawingBrush.width = parseInt(value);
        },
        clearCanvas() {
            this.canvas.clear();
            this.initCanvas(this.dialogImageUrl);
        },
        saveCanvas(){
            let that=this;
            // 清除背景图
            that.canvas.backgroundImage = null;
            that.canvas.backgroundColor = 'rgba(0,0,0,0)'
            that.canvas.renderAll();
            that.canvas.lowerCanvasEl.toBlob(function (blob) {
            let formData = new FormData();
            formData.append("image", blob, 'mask_'+openId+that.dialogImageName);
            formData.append("overwrite", "true");
            formData.append("type", "input");
            axios.post('../upload/image', formData)
                .then(function(response) {
                    let data=response.data;
                    data['url']='../view?filename='+data.name+'&type=input&subfolder=&rand='+Math.random();
                    that.paramList[that.maskKey]['fileList']=[data];
                    that.paramList[that.maskKey]['value']=data.subfolder? (data.type+'/'+data.name):(data.type+'/'+data.subfolder+'/'+data.name);
                    that.initCanvas(that.dialogImageUrl);
                })
                .catch(function(error) {
                    console.log(error);
                    ElementPlus.ElMessage.error(error);
                })
            }, "image/png");
        },
        initCanvas(backgroundUrl){
            var that = this;
            fabric.Image.fromURL(backgroundUrl, (img) => {
                if(that.canvas==null){
                    that.canvas = new fabric.Canvas("canvas", {
                        backgroundColor: "#FFFFFF",
                        isDrawingMode: true,
                    });
                    let freeDrawingBrush = new fabric.PencilBrush(that.canvas);
                    // Set initial brush settings
                    freeDrawingBrush.width = that.brushSize;
                    freeDrawingBrush.color = '#000000';
                    // Enable free drawing mode on canvas
                    that.canvas.isDrawingMode = true;
                    that.canvas.freeDrawingBrush = freeDrawingBrush;
                }
                let parentWidth = document.querySelector(".mask_edit_btn").clientWidth;
                let bili=img.width/parentWidth;
                let imgHeight=img.height/bili;
                that.canvas.setWidth(parentWidth);
                that.canvas.setHeight(imgHeight);
                that.canvas.setBackgroundImage(img, that.canvas.renderAll.bind(that.canvas),{
                    scaleX: that.canvas.width / img.width,
                    scaleY: that.canvas.height / img.height,
                });
                that.canvas.renderAll();
            });
        },
        getUserOpenId(code){
            let that=this;
            let formData = new FormData();
            formData.append("code", code);
            axios.post('../wechatauth/getUserOpenId', formData)
                .then(function(response) {
                    if(response.data.success){
                        openId=response.data.openId;
                        that.initMain();
                        if('pywebview' in window ){
                            pywebview.api.setOpenId(openId);
                        }
                    }else{
                        that.authUser('授权码校验失败，请先扫码关注获取授权码！');
                    }
                })
                .catch(function(error) {
                    console.log(error);
                    that.authUser(error);
            })
        },
        cancelTask(){
            let that=this;
            let formData = new FormData();
            formData.append("openId", openId);
            formData.append("prompt_id",that.form.prompt_id)
            axios.post('../wechatauth/cancelTask', formData)
                .then(function(response) {
                    if(response.data.success){
                        that.form.prompt_id='';
                        that.form.nodeIds=[];
                        that.form.status='prepare';
                        that.form.percenStatus='warning';
                        that.form.percentage=0;
                    }else{
                        ElementPlus.ElMessage.error(response.data.msg);
                    }
                })
                .catch(function(error) {
                    console.log(error);
                    ElementPlus.ElMessage.error(error);
            })
        },
        startTask(){
            let that=this;
            if(that.form.status!=='prepare'){
                ElementPlus.ElMessage.info('任务<'+that.form.command+'>正在运行，请勿重复操作！')
                return ;
            }
            let formData = new FormData();
            formData.append("openId", openId);
            formData.append("command", this.activeKey);
            formData.append("status", "prepare");
            that.form.openId=openId;
            that.form.command=this.activeKey;
            that.form.status="prepare";
            for(let paramKey in this.paramList){
                if(this.paramList[paramKey]?.value){
                    formData.append(paramKey,this.paramList[paramKey]?.value);
                }
            }
            axios.post('../wechatauth/addTask', formData)
                .then(function(response) {
                    console.log(response);
                    if(response.data.success){
                        that.form.status='waiting';
                        that.form.prompt_id=response.data.prompt_id;
                        that.form.nodeIds=response.data.nodeIds;
                    }else{
                        ElementPlus.ElMessage.error(response.data.msg);
                    }
                })
                .catch(function(error) {
                    console.log(error);
                    ElementPlus.ElMessage.error(error);
            })
        },
        confirmSetParam(params){
            let that=this;
            this.clickTab(params.command);
            for(let paramKey in this.paramList){
                if(params[paramKey]){
                    if(typeof params[paramKey]=='string' && params[paramKey]=='undefined'){
                        this.paramList[paramKey].value='';
                    }else if(this.paramList[paramKey].type=='slider'
                    || this.paramList[paramKey].type=='number'){
                        this.paramList[paramKey].value=parseFloat(params[paramKey]);
                    }else{
                        if(this.paramList[paramKey].type=='image'){
                            let ps=params[paramKey].split('//');
                            let url='../view?filename='+ps[1]+'&type='+ps[0]+'&subfolder=&rand='+Math.random();
                            //获取文件名称
                            this.paramList[paramKey].fileList=[{url:url,name:ps[1]}];
                        }
                        this.paramList[paramKey].value=params[paramKey];
                    }
                }
            }
        },
        async handleDownload(imgs,name) {
            let that=this;
            var zip = new JSZip();
            for (let img of imgs) {
            let fileName = img.filename;
            let { data } = await axios({
                method: 'get',
                url: img.url,
                responseType: 'blob',
            });
            zip.file(fileName, data);
            }
            zip.generateAsync({ type: 'blob' }).then(function (content) {
            let url = window.URL.createObjectURL(content);
                that.downloadFile(url, name);
            });
        },
        downloadFile(url, name) {
            let a = document.createElement('a');
            a.href = url;
            a.download = name;
            a.click();
        },
        loadHistory(){
            let that=this;
            if(this.isNotData){
                this.noMore=true;
                setTimeout(() => {
                    this.noMore=false;
                }, 1000)
                return ;
            }
            that.page_number+=1;
            that.getHistorys();
        },
        setRunTask(dataStr,prompt_id){
            let that=this;
            let params=JSON.parse(dataStr)
            this.confirmSetParam(params)
            axios.get('../api/queue')
                .then(function(response) {
                    let queue_pending=response.data.queue_pending;
                    let queue_running=response.data.queue_running;
                    for(let data of queue_running){
                        if(data[1]==prompt_id){
                            that.form.status='waiting';
                            that.form.prompt_id=prompt_id;
                            that.form.percenStatus='success';
                            that.form.nodeIds=Object.keys(data[2]);
                            return ;
                        }
                    }
                    for(let data of queue_pending){
                        if(data[1]==prompt_id){
                            that.form.status='waiting';
                            that.form.prompt_id=prompt_id;
                            that.form.nodeIds=Object.keys(data[2]);
                            return ;
                        }
                    }
                }).catch(function(error) {
                    console.log(error);
                    ElementPlus.ElMessage.error(error);
            })
            
        },
        getHistorys(){
            let that=this;
            that.loading=true;
            axios.get('../wechatauth/getHistorys?openId='+openId+'&page_number='+that.page_number)
                .then(function(response) {
                    console.log(response);
                    if(that.page_number==1){
                        that.isNotData=false;
                        that.historyList=[];
                    }
                    let datas=response.data;
                    if(datas.length>0&&datas[0][5]=='waiting'){
                        that.setRunTask(datas[0][3],datas[0][4])
                    }
                    for(let res of datas){
                        let command=JSON.parse(res[3])
                        if (res[5] == 'waiting'){
                            continue
                        }else if(res[5]=='wcomplete'){
                            command['status']='wcomplete'
                            let outputs=JSON.parse(res[8])
                            let images=[];
                            let texts=[];
                            let files=[];
                            for(let node_id in outputs){
                                let node_output = outputs[node_id]
                                if(Object.keys(node_output).indexOf("outputImg") >= 0){
                                    for(let img of node_output?.outputImg){
                                        let url='../view?filename='+img.filename+'&type='+img.type+'&subfolder='+img.subfolder+'&rand='+Math.random();
                                        images.push(url)
                                        img['url']=url;
                                        files.push(img);
                                    }
                                }else if(Object.keys(node_output).indexOf("wechat_text") >= 0){
                                    texts.push(...node_output.wechat_text);
                                }
                                
                            }
                            that.historyList.push({'prompt_id':res[4],'command':command,'images':images,'files':files,'status':res[5],'texts':texts})
                        }
                    }
                    if(datas.length<10){
                        that.isNotData=true;
                    }
                    that.loading=false;
                }).catch(function(error) {
                    console.log(error);
                    ElementPlus.ElMessage.error(error);
            })
        }
    },
    setup() {
        
    }
})

// use ElementPlus and ElementPlusIconsVue
app.use(ElementPlus)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
}

// use VueI18n
const browserLanguage = navigator.language || navigator.userLanguage; // zh-CN en-US
const languageTag = browserLanguage.split('-')[0]; // zh en
const i18n = VueI18n.createI18n({
    legacy: false, // you must set `false`, to use Composition API
    locale: languageTag, // set locale
    fallbackLocale: 'en', // set fallback locale
    messages: {},
})
app.use(i18n)
function loadLocaleMessages(locale) {
    return axios.get(`static/locales/${locale}.json`).then(response => {
        return response.data;
    });
}
async function loadLocales() {
    const locales = ['en', 'zh'];
    await Promise.all(
        locales.map(async (locale) => {
            const messages = await loadLocaleMessages(locale);
            i18n.global.setLocaleMessage(locale, messages);
        })
    );
}
loadLocales().then(() => {
    app.mount('#app');
});
</script>
<style scoped>
.el-message-box{
    div.box-title{
        width: 100%;
        text-align: center;
        font-size: large;
        color: aliceblue;
    }
    .qrcode{
        width: 100%; height: auto;
    }
    .el-input-group{
        box-shadow: 0 0 0 1px var(--el-input-border-color, var(--el-border-color)) inset;
        border-radius: var(--el-input-border-radius, var(--el-border-radius-base));
    }
    input{
        text-align: center;
    }
    .el-input-group__append{
        color: aliceblue;
    }
    margin-top: 4px;
    padding: 20px 16px;
    color: rgb(253 248 248 / 80%);
    background-color: #606266;
    border-radius: 24px;
    font-size: 13px;
    font-weight: lighter;
    border: 1px solid #606266;
}
.head-title{
    color: aliceblue;
    font-size: x-large;
    height: 52px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
}
.el-card__body,.el-card__footer{
    padding:0 ;
}
.el-upload-dragger,.el-upload-dragger.is-dragover{
    padding: 0;
    background-color: rgba(255, 255, 255, .0);
    border: none;
    border-radius: 6px;
    box-sizing: border-box;
    text-align: center;
    cursor: pointer;
    position: relative;
    overflow: hidden;
}

.image-view .el-upload--picture-card{
    display: none;
}
.el-upload-list--picture-card .el-upload-list__item,.el-upload--picture-card{
    width: 100px;
    height: 100px;
}
.el-menu--horizontal {
  --el-menu-horizontal-height: 100px;
}
.el-form-item__label,.el-checkbox__label,.el-radio__label,.el-input__inner,.el-statistic__head,.el-statistic__number{
    color: rgba(255, 255, 255, .8);
}
.el-input__wrapper{
    font-weight: lighter;
    position: relative;
    background-color: rgba(255, 255, 255, .05);
    color: rgba(255, 255, 255, .8);
    border-radius: 9px;
    font-size: 13px;
    border: 1px solid transparent;
}
.el-textarea__inner{
    font-weight: lighter;
    position: relative;
    background-color: rgba(255, 255, 255, .05);
    color: rgba(255, 255, 255, .8);
    border-radius: 9px;
    font-size: 13px;
    border: 1px solid transparent;
}
.el-card,.el-card__body,.el-card__header,.el-card__footer{
    color: rgba(255, 255, 255, .8);
    background-color: rgba(255, 255, 255, .0);
    border: 0px solid transparent;
}
.el-input-group__append,.el-switch__core,.el-input-number__decrease,.el-input-number__increase,.el-upload--picture-card{
    background-color: rgba(255, 255, 255, .05);
}
.el-textarea .el-input__count{
    color: rgba(255, 255, 255, .8);
    background-color: rgba(255, 255, 255, 0);
}
.el-icon{
    color: rgba(255, 255, 255, .8);
}
.el-popper.is-pure{
    padding: 13px 0;
    background: rgba(255, 255, 255, .1);
    color: #fff;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    box-shadow: 0 4px 40px rgba(2, 10, 29, .4);
    border-radius: 9px;
}

.el-select-dropdown__item{
    padding: 5px 20px 5px 12px;
    position: relative;
    background: transparent;
    color: #fff;
    display: block;
    min-height: 32px;
    padding: 5px 12px;
    color: rgba(250, 250, 250, 0.88);
    font-weight: normal;
    font-size: 14px;
    line-height: 1.5714285714285714;
    box-sizing: border-box;
    cursor: pointer;
    border-radius: 4px;
}
.el-select-dropdown__item.hover, .el-select-dropdown__item:hover{
    background: rgba(255, 255, 255, .05);
}
.el-select-dropdown__item.selected{
    color: #fff;
}
.el-select-dropdown__item.selected:after {
    width: 16px;
    height: 16px;
    position: absolute;
    content: "";
    background: url(https://staticsns.cdn.bcebos.com/amis/2024-1/1704594047813/selected.png);
    background-size: 100% 100%;
    right: 8px;
    top: 8px;
}
.el-button.is-disabled, .el-button.is-disabled:focus, .el-button.is-disabled:hover{
    position: relative;
    background: linear-gradient(to bottom right, rgb(229, 250, 87), rgb(64, 252, 67));
    font-size: 16px;
    font-weight: 900;
    text-align: center;
    line-height: 19.6px;
    border-radius: 48px;
    color: #000;
    cursor: not-allowed;
}
.el-carousel__container{
    height: 100%;
    width: 100%;
}
</style>
</html>
